#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/sem.h>
#include <sys/ipc.h>
#include <inttypes.h>
#include <time.h>
#include <logbase.h>
#include <cstring.h>
#include <hexstr.h>
#include <genrand.h>

#define encDesFixKey "\x59\x77\x44\x51\x38\x4b\x66\x4e"

int hex2Str(const char *inbuf, int insize, char *outbuffer, int outsize)
{
    const char *tmpConvertString = "0123456789ABCDEF";
    if (outsize < insize * 2)
    {
        return 0;
    }
    for (int i = 0; i < insize; i++)
    {
        outbuffer[i * 2] = tmpConvertString[(inbuf[i] >> 4) & 0xf];
        outbuffer[i * 2 + 1] = tmpConvertString[(inbuf[i] >> 0) & 0xf];
    }
    return insize * 2;
}

char str2Char(const char *cstr)
{
    char tmpc = 0;
    if (cstr[0] >= '0' && cstr[0] <= '9')
    {
        tmpc = cstr[0] - '0';
    }
    else if (cstr[0] >= 'A' && cstr[0] <= 'F')
    {
        tmpc = 0X0A + cstr[0] - 'A';
    }
    else if (cstr[0] >= 'a' && cstr[0] <= 'f')
    {
        tmpc = 0X0A + cstr[0] - 'a';
    }
    tmpc <<= 4;
    if (cstr[1] >= '0' && cstr[1] <= '9')
    {
        tmpc += cstr[1] - '0';
    }
    else if (cstr[1] >= 'A' && cstr[1] <= 'F')
    {
        tmpc += 0X0A + cstr[1] - 'A';
    }
    else if (cstr[1] >= 'a' && cstr[1] <= 'f')
    {
        tmpc += 0X0A + cstr[1] - 'a';
    }
    return tmpc;
}
int str2Hex(const char *inbuf, int insize, char *outbuffer, int outsize)
{
    if (outsize < insize / 2)
    {
        return 0;
    }
    for (int i = 0; i < insize / 2; i++)
    {
        outbuffer[i] = str2Char(inbuf + i * 2);
    }
    return insize * 2;
}

void Des(unsigned char *MsgIn, unsigned char *MsgOut, const unsigned char *Key, unsigned char Mode);
#if 0
// input hex buffer, out hex string
int encHex2Str(char *ihexb, int isize, char *ohexs, int osize, const char *edkey)
{
    int i;
    char tmpenc[8];
    if (!(isize % 8 == 0 && osize == isize * 2))
    {
        return 0;
    }
    ihexb[0] = 0;
    for(i = 1; i < isize; i++)
    {
        ihexb[0] ^= ihexb[i];
    }
    for (i = 0; i < isize / 8; i++)
    {
        Des((unsigned char *)ihexb + i * 8, (unsigned char *)tmpenc, (unsigned char *)edkey, 0);
        hex2Str(tmpenc, sizeof(tmpenc), ohexs + i * 16, 16);
    }
    return osize;
}

int decStr2Hex(char *ihexs, int isize, char *ohexb, int osize, const char *edkey)
{
    int i;
    char tmpdec[8], tmpcrc = 0;
    if (!(isize % 16 == 0 && osize == isize / 2))
    {
        return 0;
    }
    str2Hex(ihexs, isize, ohexb, osize);
    for (i = 0; i < osize / 8; i++)
    {
        Des((unsigned char *)ohexb + i * 8, (unsigned char *)tmpdec, (unsigned char *)edkey, 1);
        memcpy(ohexb + i * 8, tmpdec, 8);
    }
    for (i = 1; i < osize; i++)
    {
        tmpcrc ^= ohexb[i];
    }
    if(tmpcrc != ohexb[0])
    {
        logerrorc("");
        return 0;
    }
    return osize;
}
#endif
void simpleEnc(char *MsgIn, char *MsgOut, const char *Key, char Mode)
{
    int i;
    if (!Mode)
    {
        for (i = 0; i < 8; i++)
        {
            MsgOut[i] = MsgIn[i] + Key[i];
            if (i > 0)
            {
                MsgOut[i] ^= MsgOut[i - 1];
            }
        }
    }
    else
    {
        for (i = 7; i >= 0; i--)
        {
            if (i > 0)
            {
                MsgOut[i] = MsgIn[i] ^ MsgIn[i - 1];
            }
            else
            {
                MsgOut[i] = MsgIn[i];
            }
            MsgOut[i] = MsgOut[i] - Key[i];
        }
    }
}
int encHex2Str(char *ihexb, int isize, char *ohexs, int osize, const char *edkey)
{
    int i;
    char tmpenc[8];
    if (!(isize % 8 == 0 && osize == isize * 2))
    {
        return 0;
    }
    ihexb[0] = 0;
    for (i = 1; i < isize; i++)
    {
        ihexb[0] ^= ihexb[i];
    }
    for (i = 0; i < isize / 8; i++)
    {
        simpleEnc(ihexb + i * 8, tmpenc, edkey, 0);
        hex2Str(tmpenc, sizeof(tmpenc), ohexs + i * 16, 16);
    }
    return osize;
}

int decStr2Hex(char *ihexs, int isize, char *ohexb, int osize, const char *edkey)
{
    int i;
    char tmpdec[8], tmpcrc = 0;
    if (!(isize % 16 == 0 && osize == isize / 2))
    {
        return 0;
    }
    str2Hex(ihexs, isize, ohexb, osize);
    for (i = 0; i < osize / 8; i++)
    {
        simpleEnc(ohexb + i * 8, tmpdec, edkey, 1);
        memcpy(ohexb + i * 8, tmpdec, 8);
    }
    for (i = 1; i < osize; i++)
    {
        tmpcrc ^= ohexb[i];
    }
    if (tmpcrc != ohexb[0])
    {
        logerrorc("");
        return 0;
    }
    return osize;
}
#define checkBuffSize 4
int main(int argsize, const char **args)
{
    char tmporg[16], tmpdec[16], tmpprt[32], tmpcmp[16] = "\xD4\x63\x36\x0D\x08\x5D\xBE\x67";
    simpleEnc(tmpcmp, tmporg, encDesFixKey, 0);
    hex2Str(tmporg, sizeof(tmporg), tmpprt, sizeof(tmpprt));
    logdebugc("%.*s", 16, tmpprt);
    simpleEnc(tmporg, tmpdec, encDesFixKey, 1);
    hex2Str(tmpdec, sizeof(tmpdec), tmpprt, sizeof(tmpprt));
    logdebugc("%.*s", 16, tmpprt);

    logdebugc("");
    for (int i = 0; i < checkBuffSize; i++)
    {
        genRandHexBuf(tmpcmp, sizeof(tmpcmp));
        if (checkBuffSize < 5)
        {
            hex2Str(tmpcmp, sizeof(tmpcmp), tmpprt, sizeof(tmpprt));
            logdebugc("%.*s", (int)sizeof(tmpprt), tmpprt);
        }
        memcpy(tmporg, tmpcmp, sizeof(tmporg));
        if (checkBuffSize < 5)
        {
            hex2Str(tmporg, sizeof(tmporg), tmpprt, sizeof(tmpprt));
            logdebugc("org:%.*s", (int)sizeof(tmpprt), tmpprt);
        }

        encHex2Str(tmporg, sizeof(tmporg), tmpprt, sizeof(tmpprt), encDesFixKey);
        if (checkBuffSize < 5)
        {
            logdebugc("enc:%.*s", (int)sizeof(tmpprt), tmpprt);
        }

        decStr2Hex(tmpprt, sizeof(tmpprt), tmpdec, sizeof(tmpdec), encDesFixKey);
        if (checkBuffSize < 5)
        {
            hex2Str(tmpdec, sizeof(tmpdec), tmpprt, sizeof(tmpprt));
            logdebugc("dec:%.*s", (int)sizeof(tmpprt), tmpprt);
            hex2Str(tmpcmp, sizeof(tmpcmp), tmpprt, sizeof(tmpprt));
            logdebugc("dec:%.*s", (int)sizeof(tmpprt), tmpprt);
        }

        if (memcmp(tmpcmp + 1, tmpdec + 1, sizeof(tmpcmp) - 1) != 0)
        {
            logerrorc("");
        }
    }
    logdebugc("");
    return 0;
}